#include <assert.h>
#include <stdio.h>
#include <sysexits.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include <libxml/xmlsave.h>

#include "../mcx/mcx.h"
#include "prepaid.h"

const char tmpbase[] = LOCALSTATEDIR "/prepaid/keys";
const char permbase[] = LOCALSTATEDIR "/prepaid/authorities";

const char *pp_keydir() {
  return tmpbase;
}

const char *pp_authdir() {
  return permbase;
}
  
unsigned pp_addkey(xmlNodePtr key) {
  unsigned index;
  int i, fd;
  struct stat st;
  char *tmp, *perm;
  xmlSaveCtxtPtr ctxt;
  xmlDocPtr doc;
  xmlNodePtr root;

  tmp = alloca(strlen(pp_keydir()) + 20);
  perm = alloca(strlen(pp_authdir()) + 20);

  for(i = 0; i < 100; i++) {
    index = rand() & 0x3ff;
    sprintf(tmp, "%s/%04d.xml", pp_keydir(), index);
    sprintf(perm, "%s/%04d.xml", pp_authdir(), index);
    if(stat(tmp, &st) && (ENOENT == errno) && stat(perm, &st) && (ENOENT == errno))
      break;
  }
  fd = open(tmp, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR);
  if(fd < 0) {
    perror("open");
    exit(EX_OSERR);
  }

  doc = xmlNewDoc("1.0");
  root = xmlNewDocNode(doc, NULL, "wrapper", NULL);
  xmlDocSetRootElement(doc, xmlDocCopyNode(key, doc, 1));
  ctxt = xmlSaveToFd(fd, "UTF-8", XML_SAVE_NO_EMPTY|XML_SAVE_NO_DECL);
  xmlSaveDoc(ctxt, doc);
  xmlSaveClose(ctxt);
  close(fd);
  return index;
}

xmlDocPtr pp_pay(int index, char *currency, char *amount) {
  char *ptr;
  xmlDocPtr ki, auth;
  int fd;
  xmlSaveCtxtPtr ctxt;
  xmlNodePtr root, sig;
  xmlSecKeyPtr key;
  
  ptr = alloca(strlen(pp_keydir()) + 20);
  sprintf(ptr, "%s/%04d.xml", pp_keydir(), index);
  ki = validateXmlFile(URI_SCHEMA_CHARON, ptr);
  auth = mcx_authority(xmlDocGetRootElement(ki), currency, amount);
  root = xmlDocGetRootElement(auth);
  key = mcx_loadkey(SYSCONFDIR "/key.rsa");
  assert(key);
  sig = mcx_sign(root, key);
  assert(sig);
  //  xmlAddChild(root, sig);
  ptr = alloca(strlen(pp_authdir()) + 20);
  sprintf(ptr, "%s/%04d.xml", pp_authdir(), index);
  fd = open(ptr, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR);
  if(fd < 0) {
    perror("open");
    exit(EX_OSERR);
  }
  ctxt = xmlSaveToFd(fd, "UTF-8", XML_SAVE_NO_EMPTY|XML_SAVE_NO_DECL);
  xmlSaveDoc(ctxt, auth);
  xmlSaveClose(ctxt);
  close(fd);
  return auth;
}

static xmlDocPtr pp_getfile(const char *path, int index) {
  char *file;

  file = alloca(strlen(path) + 20);
  sprintf(file, "%s/%04d.xml", path, index);
  return validateXmlFile(URI_SCHEMA_CHARON, file);
}

xmlDocPtr pp_getkey(int index) {
  return pp_getfile(pp_keydir(), index);
}

xmlDocPtr pp_getauth(int index) {
  return pp_getfile(pp_authdir(), index);
}
